package com.ifp.opengate.boot.filter;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ifp.adapter.common.AdapterCanstants;
import com.ifp.core.context.ClogicContext;
import com.ifp.core.exception.BaseException;
import com.ifp.core.log.Trace;
import com.ifp.core.util.StringUtil;
import com.ifp.opengate.boot.bean.OpenGateRoute;
import com.ifp.opengate.boot.bean.ValidatorForm;
import com.ifp.opengate.boot.bean.access.IPBlackAndWhiteBean;
import com.ifp.opengate.boot.constants.Constants;
import com.ifp.opengate.boot.constants.Event;
import com.ifp.opengate.boot.dao.ApiLogMapper;
import com.ifp.opengate.boot.decode.RequestMessageTool;
import com.ifp.opengate.boot.emum.ErrorEnum;
import com.ifp.opengate.boot.entity.ApiLog;
import com.ifp.opengate.boot.exception.AccessControlException;
import com.ifp.opengate.boot.task.*;
import com.ifp.opengate.boot.utils.MessageUtil;
import com.ifp.opengate.boot.utils.RequestUtil;

import net.sf.json.JSONObject;
import reactor.core.publisher.Mono;

/**
 * Created by mogs on 2019/4/17. API 准入控制
 */
@Component
public class ApiGlobalFilter implements GlobalFilter, Ordered {
    /**
     * 系统api（无产品属性），多个使用|分割
     */
    @Value("${open.gate.sys.api:api}")
    private String sysApi;
    @Value("${opengate_group_api_group_prefix:prefix}")
    private String apiGroupPrefix;

    @Value("${opengate_header_params_template_info_prefix:info_prefix}")
    private String headerParamPrefix;
    @Autowired
    private MessageUtil messageUtil;

    @Autowired
    private AccessCacheDataSyncTask accessCacheDataSyncHandler;

    @Autowired
    private ApiDeployTask apiDeployTask;

    @Autowired
    private ApiGroupCacheDataTask apiGroupCacheDataTask;

    @Autowired
    private ConnectorCacheDataTask connectorCacheDataTask;

    @Autowired
    IPBlackAndWhiteBean ipBlackAndWhiteBean;

    /**
     * 校验参数
     */
    @Autowired
    RequestMessageTool requestMessageTool;

    @Autowired
    HeaderTemplateCacheTask headerTemplateCacheTask;

    @Autowired
    ApiLogMapper apiLogMapper;

    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
        Trace.logInfo(Trace.MODULE_FILTER, "ApiGlobalFilter start filter....");
        ServerHttpRequest request = serverWebExchange.getRequest();
        ClogicContext clogicContext = (ClogicContext)serverWebExchange.getAttributes().get(Constants.CL_CONTEXT);
        Map<String, Object> dataMap = clogicContext.getDataMap();
        Map<String, Object> headerMap = (Map<String, Object>)dataMap.get(AdapterCanstants.HEADER);

        // 接口统一识别码校验
        // chechInterfaceCode(request, ErrorEnum.interfaceCodeError);

        // 初始化appId
        String appId = this.getAndCheckParam(request, clogicContext, Constants.APP_ID, "接口编号不存在");
        // appId黑名单
        chechIdBlackList(appId, Event.APPID_BLACK_MAP, ErrorEnum.accessAppIdBlackError);
        // mac黑名单
        String mac = this.getValueByKey(request, clogicContext, "devDataId");
        chechIdBlackList(mac, Event.MAC_BLACK_MAP, ErrorEnum.accessMacBlackError);
        // mobile黑名单
        String mobile = this.getValueByKey(request, clogicContext, "devDataPhoneNo");
        chechIdBlackList(mobile, Event.MOBILE_BLACK_MAP, ErrorEnum.accessMobileBlackError);
        // email黑名单
        /*String email1 = this.getValueByKey(request, clogicContext, Event.EMAIL_BLACK_MAP);
        chechIdBlackList(email, Event.EMAIL_BLACK_MAP, ErrorEnum.accessEmailBlackError);*/
        // userId黑名单
        String userId = this.getValueByKey(request, clogicContext, Event.USERID_BLACK_MAP);
        chechIdBlackList(userId, Event.USERID_BLACK_MAP, ErrorEnum.accessUserIdBlackError);

        String apiVersion = this.getAndCheckParam(request, clogicContext, Constants.VERSION, "接口版本号");
        serverWebExchange.getAttributes().put(Constants.API_VERSION, apiVersion);
        // 获取app信息缓存
        String appInfoKey = Constants.OPEN_GATE_CACHE_NAME + "_" + Constants.APP_INFO_PREFIX + appId;
        Map<Object, Object> appInfo = accessCacheDataSyncHandler.getAccessParamMap().get(appInfoKey);
        if (null == appInfo) {

            // 组装appInfo信息
            String merchantNo = (String)headerMap.get("appId");
            String appSecret = (String)headerMap.get("appSecret");
            if (StringUtils.isEmpty(merchantNo) || StringUtils.isEmpty(appSecret)) {
                Trace.logError(Trace.MODULE_INTERCEPTOR, "未找到该app[{}]的缓存配置信息", appId);
                throw new AccessControlException(ErrorEnum.appInfoNotFoundError.code(),
                    ErrorEnum.appInfoNotFoundError.msg());
            }
            appInfo = new HashMap<>(16);
            appInfo.put("merchantNo", merchantNo);
            appInfo.put("appSecret", appSecret);
            appInfo.put("merchantState", 0);
            appInfo.put("ISTRUN", 0);

        }
        Trace.logInfo(Trace.MODULE_INTERCEPTOR, " appInfo >>" + appInfo.toString());

        // 商户号
        String merchantNo = String.valueOf(appInfo.get(Constants.MERCHANT_NO));
        Trace.logInfo(Trace.MODULE_INTERCEPTOR, " merchantNo >>" + merchantNo);

        // TODO: thirdPartyId黑名单
        // String thirdPartyId = this.getValueByKey(request, clogicContext, Event.THIRDPARTYID_BLACK_MAP);
        chechIdBlackList(merchantNo, Event.THIRDPARTYID_BLACK_MAP, ErrorEnum.accessThirdPartyIdBlackError);

        // 商户状态
        String merchantState = String.valueOf(appInfo.get(Constants.MERCHANT_STATE));
        Trace.logInfo(Trace.MODULE_INTERCEPTOR, " merchantState >>" + merchantState);
        if (Constants.MERCHANT_DEL.equals(merchantState) || Constants.MERCHANT_FREEZE.equals(merchantState)) {
            throw new AccessControlException(ErrorEnum.merchantFreezedOrDel.code(),
                String.format(ErrorEnum.merchantFreezedOrDel.msg(), merchantNo));
        }
        String isTurn = String.valueOf(appInfo.get(Constants.ISTRUN));
        if (!StringUtil.hasText(isTurn)) {
            isTurn = this.getHeaderValue(request, Constants.ISTRUN);
        }
        if (!StringUtil.hasText(isTurn)) {
            isTurn = this.getParamValue(request, Constants.ISTRUN);
        }
        // 获取api信息缓存
        String transCode = clogicContext.getTransCode();
        Trace.logInfo(Trace.MODULE_INTERCEPTOR, "transCode-->" + transCode);
        String apiInfoKey = Constants.API_INFO_PREFIX + transCode;
        Map<Object, Object> apiInfo = apiDeployTask.getApiInfoMap()
            .get(Constants.OPEN_GATE_CACHE_NAME + "_" + apiInfoKey + Constants.BOTTOM_LINE + apiVersion);
        Trace.logInfo(Trace.MODULE_INTERCEPTOR, "--------------------------------" + Constants.OPEN_GATE_CACHE_NAME
            + "_" + apiInfoKey + Constants.BOTTOM_LINE + apiVersion);
        Trace.logInfo(Trace.MODULE_INTERCEPTOR, "apiInfo-->" + apiInfo);
        if (null == apiInfo || apiInfo.isEmpty()) {
            // TODO： 接口不存在
            Trace.logError(Trace.MODULE_INTERCEPTOR, "未找到该api[{}]的缓存配置信息", transCode);
            throw new AccessControlException(ErrorEnum.apiSateError.code(),
                String.format(ErrorEnum.apiSateError.msg(), transCode));
        }
        Route route = serverWebExchange.getAttribute(GATEWAY_ROUTE_ATTR);
        OpenGateRoute openGateRoute = connectorCacheDataTask.getRouteOfMap().get(route.getId());
        if (openGateRoute == null || openGateRoute.getStatus() != 1) {
            Trace.logError(Trace.MODULE_INTERCEPTOR, "未找到该api[{}]的缓存配置信息", transCode);
            throw new AccessControlException(ErrorEnum.apiSateError.code(),
                String.format(ErrorEnum.apiSateError.msg(), transCode));
        }
        LambdaQueryWrapper<ApiLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApiLog::getRequestId, dataMap.get("requestId"));
        ApiLog apiLog = new ApiLog();
        if (openGateRoute.getRouteId() != null) {
            apiLog.setRouteId(openGateRoute.getRouteId());
        }
        if (openGateRoute.getRouteName() != null) {
            apiLog.setRouteName(openGateRoute.getRouteName());
        }
        if(StringUtils.isNotBlank(request.getURI().getPath())){
            apiLog.setPath(request.getURI().getPath());
        }
        apiLog.setIsSuccess(1);
        apiLogMapper.update(apiLog, queryWrapper);
        // 校验请求参数
        String apiType = RequestUtil.getHeaderValue(request, "apiType");
        if (StringUtils.isBlank(apiType) || !apiType.equalsIgnoreCase((String)apiInfo.get("apiType"))) {
            Trace.logError(Trace.MODULE_INTERCEPTOR, "请求方式异常，上送渠道：{}，apiType：{}", apiType, apiInfo.get("apiType"));
            throw new AccessControlException(ErrorEnum.apiChannelError.code(),
                String.format(ErrorEnum.apiChannelError.msg(), transCode));
        }
        // 校验SDK版本号
        if ("sdk".equalsIgnoreCase(apiType)) {
            String sdkVsersion = RequestUtil.getHeaderValue(request, "sdkVersion");
            Trace.logInfo(Trace.MODULE_COMMON, "上送的sdkVersion{}-->", sdkVsersion);
            /*if(StringUtils.isBlank(sdkVsersion)) {
            	throw new AccessControlException(ErrorEnum.checkSdkNotSendVersionError.code(), ErrorEnum.checkSdkNotSendVersionError.msg());
            }
            String curSdkVsersion = (String) clogicContext.getTempMap().get(Constants.GW_TEMP_KEY + "sdkVersion");
            if(!sdkVsersion.equals(curSdkVsersion)) {
            	throw new AccessControlException(ErrorEnum.checkSdkVersionError.code(), ErrorEnum.checkSdkVersionError.msg());
            }*/
        }

        // 获取API分组Id
        String serviceGroupId = (String)apiInfo.get(Constants.API_GROUP_ID);
        Map<Object, Object> apiGroupInfo = null;
        if (StringUtil.hasText(serviceGroupId)) {
            // 获取分组信息
            apiGroupInfo = apiGroupCacheDataTask.getApiGroupInfoMap().get(apiGroupPrefix + serviceGroupId);
            // 将分组信息保存clogic备份用
            clogicContext.getTempMap().put(Constants.API_GROUP, apiGroupInfo);

        }

        /* // api所属产品
        String prdId = String.valueOf(apiInfo.get(Constants.PRD_ID));
        String productInfo = Constants.OPEN_GATE_CACHE_NAME + "_" + Constants.PRODUCT_INFO_ALL;
        //产品是否为上架状态
        Map<Object, Object> productInfoList = accessCacheDataSyncHandler.getAccessParamMap().get(productInfo);
        if (productInfoList.containsKey(prdId)) {
            String productState = String.valueOf(productInfoList.get(prdId));
            if (Constants.PRD_NEW.equals(productState) || Constants.PRD_GROUNDING.equals(productState)) {
                Trace.logInfo(Trace.MODULE_INTERCEPTOR, "productState-->" + productState);
            } else {
                Trace.logError(Trace.MODULE_INTERCEPTOR, "productState-->" + productState);
                throw new AccessControlException(ErrorEnum.prdSateError.code(),
                        String.format(ErrorEnum.prdSateError.msg(), prdId));
            }
        } else {
            throw new AccessControlException(ErrorEnum.prdNoAuthorityError.code(),
                    String.format(ErrorEnum.prdNoAuthorityError.msg(), prdId));
        }
        String appPrdKey = Constants.APP_PRD_PREFIX + prdId;
        // app是否有该产品权限
        String prdName = String.valueOf(appInfo.get(appPrdKey));
        if (StringUtils.isBlank(prdName) || "null".equals(prdName)) {
            // 系统api不校验产品权限
            if (null != sysApi && sysApi.indexOf(transCode) > -1) {
                prdName = "";
            } else {
                throw new AccessControlException(ErrorEnum.apiNoAuthorityError.code(),
                        String.format(ErrorEnum.apiNoAuthorityError.msg(), transCode));
            }
        }*/
        // 初始化报文长度
        if (StringUtil.hasText(request.getQueryParams().containsKey(Constants.CONTEXT_LENGTH))) {
            clogicContext.setValue(Constants.CONTEXT_LENGTH, this.getParamValue(request, Constants.CONTEXT_LENGTH));
        } else {
            clogicContext.setValue(Constants.CONTEXT_LENGTH, clogicContext.getDataMap().toString().length());
        }
        // 取出app密钥的（临时处理）
        String appSecret = String.valueOf(appInfo.get(Constants.APP_SECRET));
        if (!StringUtil.hasText(appSecret)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "密钥"));
        }
        Object protocolMap = apiInfo.get(serverWebExchange.getAttributes().get("schema"));
        Trace.logError(Trace.MODULE_INTERCEPTOR, "schema---->" + serverWebExchange.getAttributes().get("schema"));
        if (!(protocolMap instanceof Map)) {
            Trace.logError(Trace.MODULE_INTERCEPTOR, "未找到该api[{}]的缓存配置信息", transCode);
            throw new AccessControlException(ErrorEnum.apiSateError.code(), ErrorEnum.apiSateError.msg());
        }
        /*// add by zy if判断 测试,白名单不做校验
        if(!WhiteListCaheUtil.getCacheCheckWhiteFromBean(ipBlackAndWhiteBean.getAppWhtelist(), appId, "CipherFilter", clogicContext)) {
        	checkSecret(merchantNo,clogicContext);
        }*/

        // 订阅组（RPC）
        String subscribeGroup = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_GROUP));
        // Interface
        String subscribeClass = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_CLASS));
        // Retries
        String subscribeRetries = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_RETRIES));
        // methodName
        String subscribeMethodName = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_METHOD_NAME));
        // 订阅服务（交易编码）
        String subscribeServiceCode = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_SERVICE_CODE));
        // 订阅的服务所用协议
        String subscribeProtocol = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_PROTOCOL));
        // 订阅系统（内部通讯系统）
        String apiName = String.valueOf(apiInfo.get(Constants.API_NAME));
        // 订阅服务版本
        String subcribeVersion = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_VERSION));
        String subscribeSystemId = String.valueOf(((Map)protocolMap).get(Constants.SUBCRIBE_SYSTEM_ID));
        clogicContext.getTempMap().put(Constants.API_NAME, apiName);
        clogicContext.getTempMap().put(Constants.APP_ID, appId);
        // clogicContext.getTempMap().put(Constants.PRD_ID, prdId);
        // clogicContext.getTempMap().put(Constants.PRD_NAME, prdName);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_GROUP, subscribeGroup);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_CLASS, subscribeClass);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_RETRIES, subscribeRetries);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_METHOD_NAME, subscribeMethodName);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_SERVICE_CODE, subscribeServiceCode);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_SYSTEM_ID, subscribeSystemId);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_PROTOCOL, subscribeProtocol);
        clogicContext.getTempMap().put(Constants.MERCHANT_NO, merchantNo);
        clogicContext.getTempMap().put(Constants.API_VERSION, apiVersion);
        clogicContext.getTempMap().put(Constants.SUBCRIBE_VERSION, subcribeVersion);

        // 判断是否映射标志
        clogicContext.getTempMap().put(Constants.ISTRUN, isTurn);
        // 临时处理
        clogicContext.getTempMap().put(Constants.APP_SECRET, appSecret);
        // 设置商户号，流控，访问量等拦截器要用到的
        clogicContext.setValue(Constants.MERCHANT_NO, merchantNo);

        headerMap.put(Constants.MERCHANT_NO, merchantNo);
        headerMap = checkHeader(headerMap, apiGroupInfo, appSecret);
        // 响应流水：返回商户以及作为调用行内系统的全局流水
        try {
            headerMap.put(Constants.RESPONSE_ID, messageUtil.getTransGlobalFlow());
        } catch (BaseException e) {
            e.printStackTrace();
        }
        dataMap.put(AdapterCanstants.HEADER, headerMap);
        return gatewayFilterChain.filter(serverWebExchange);
    }

    /**
     * 密钥的获取及校验
     * 
     * @param merchantNo
     * @param clogicContext
     */
    private void checkSecret(String merchantNo, ClogicContext clogicContext) {
        Map<String, Object> dataMap = clogicContext.getDataMap();

        String secretInfoKey = Constants.OPEN_GATE_CACHE_NAME + "_" + Constants.SECRET_INFO_PREFIX + merchantNo;
        Map<Object, Object> secretInfoMap = accessCacheDataSyncHandler.getAccessParamMap().get(secretInfoKey);
        Trace.logInfo(Trace.MODULE_COMMON, "校验商户密钥信息，密钥key：{}", secretInfoKey);
        if (secretInfoMap == null) {
            throw new AccessControlException(ErrorEnum.appSecretNotFoundError.code(),
                ErrorEnum.appSecretNotFoundError.msg());
        }

        // 密钥生效时间
        String merchatValidTime = String.valueOf(secretInfoMap.get(Constants.MER_VALID_START_TIME));
        // 密钥失效效时间
        String merchantInvalidTime = String.valueOf(secretInfoMap.get(Constants.MER_INVALID_END_TIME));
        if (StringUtil.hasText(merchatValidTime) && StringUtil.hasText(merchantInvalidTime)) {
            String currentTime = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
            if (!RequestUtil.checkValidTime(merchatValidTime, merchantInvalidTime, currentTime)) {
                throw new AccessControlException(ErrorEnum.appSecretKeyError.code(), ErrorEnum.appSecretKeyError.msg());
            }
        }

        // merchantSignPublicKeyName、merchantEncryptPublicKeyName
        // 、platformEncryptPrivateKeyName、platformSignPrivateKeyName、
        String merchantSignPublicKeyName = String.valueOf(secretInfoMap.get(Constants.MER_SIGN_PUBLIC_KEY_NAME));
        if (!StringUtil.hasText(merchantSignPublicKeyName)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "验签公钥"));
        }
        String merchantSignPublicKeyValue = String.valueOf(secretInfoMap.get(Constants.MER_SIGN_PUBLIC_KEY_VALUE));
        if (!StringUtil.hasText(merchantSignPublicKeyName)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "验签公钥"));
        }
        String merchantEncryptPublicKeyName = String.valueOf(secretInfoMap.get(Constants.MER_CIPHER_PUBLIC_KEY_NAME));
        if (!StringUtil.hasText(merchantSignPublicKeyName)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "解密公钥"));
        }
        String merchantEncryptPublicKeyValue = String.valueOf(secretInfoMap.get(Constants.MER_CIPHER_PUBLIC_KEY_VALUE));
        if (!StringUtil.hasText(merchantSignPublicKeyName)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "解密公钥"));
        }
        String platformEncryptPrivateKeyName =
            String.valueOf(secretInfoMap.get(Constants.PLAT_CIPHER_PRIVATE_KEY_NAME));
        if (!StringUtil.hasText(merchantSignPublicKeyName)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "加密密钥"));
        }
        String platformSignPrivateKeyName = String.valueOf(secretInfoMap.get(Constants.PLAT_SIGN_PRIVATE_KEY_NAME));
        if (!StringUtil.hasText(merchantSignPublicKeyName)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), "加签密钥"));
        }

        clogicContext.getTempMap().put(Constants.MER_SIGN_PUBLIC_KEY_VALUE,
            new String(Base64.getDecoder().decode(merchantSignPublicKeyValue)));
        clogicContext.getTempMap().put(Constants.MER_SIGN_PUBLIC_KEY_NAME, merchantSignPublicKeyName);
        clogicContext.getTempMap().put(Constants.MER_CIPHER_PUBLIC_KEY_VALUE,
            new String(Base64.getDecoder().decode(merchantEncryptPublicKeyValue)));
        clogicContext.getTempMap().put(Constants.MER_CIPHER_PUBLIC_KEY_NAME, merchantEncryptPublicKeyName);
        clogicContext.getTempMap().put(Constants.PLAT_CIPHER_PRIVATE_KEY_NAME, platformEncryptPrivateKeyName);
        clogicContext.getTempMap().put(Constants.PLAT_SIGN_PRIVATE_KEY_NAME, platformSignPrivateKeyName);
    }

    private void chechInterfaceCode(ServerHttpRequest request, ErrorEnum accessappidblackerror) {
        String uri = request.getURI().getPath();
        String interfaceCodeStr = uri.substring(uri.lastIndexOf('/') + 1);
        if (StringUtils.isBlank(interfaceCodeStr)) {
            // URL不规范
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        if (interfaceCodeStr.length() != 24) {
            // 长度为24个字符
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        String str1 = interfaceCodeStr.substring(0, 2); // 2
        String str2 = interfaceCodeStr.substring(2, 8); // 6
        String str3 = interfaceCodeStr.substring(8, 10); // 2
        String str4 = interfaceCodeStr.substring(10, 16); // 6
        String str5 = interfaceCodeStr.substring(16, 22); // 6
        String str6 = interfaceCodeStr.substring(22, 24); // 2
        if (interfaceCodeStr.length() != 24) {
            // 长度为24个字符
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        if (!"OP".equals(str1)) {
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        if (!"C32156".equals(str2)) {
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        if (!("00".equals(str3) || "01".equals(str3) || "02".equals(str3))) {
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        Pattern pattern4 = Pattern.compile("\\d{6}");
        if (!pattern4.matcher(str4).matches()) {
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        if (!pattern4.matcher(str5).matches()) {
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
        if (!"00".equals(str6)) {
            throw new AccessControlException(ErrorEnum.interfaceCodeError.code(), ErrorEnum.interfaceCodeError.msg());
        }
    }

    /**
     * 校验报文头
     *
     * @param headerMap
     * @param apiGroupInfo
     * @param appSecret
     */
    private Map<String, Object> checkHeader(Map<String, Object> headerMap, Map<Object, Object> apiGroupInfo,
        String appSecret) {
        // 是否需要校验报文头,没有分组就不需要校验
        if (null != apiGroupInfo) {
            Object checkHeader = apiGroupInfo.get("checkHeader");
            if ("1".equals(checkHeader)) {
                // 获取报文头校验表单
                ConcurrentMap<String, List<ValidatorForm>> headerCache = headerTemplateCacheTask.getHeaderCache();
                Object templateId = apiGroupInfo.get("templateId");
                if (!StringUtil.hasText(templateId)) {
                    throw new AccessControlException(ErrorEnum.notHaveTemplate.code(), ErrorEnum.notHaveTemplate.msg());
                }
                List<ValidatorForm> validatorForms = headerCache.get(headerParamPrefix + templateId);
                if (null != validatorForms) {
                    try {
                        // 校验报文头
                        return requestMessageTool.packRequestMessage(appSecret, validatorForms,
                            JSONObject.fromObject(headerMap));
                    } catch (AccessControlException e) {
                        Trace.log(Trace.MODULE_INTERCEPTOR, Trace.LEVEL_ERROR, "this error!!==========>>>{}", e);
                        throw new AccessControlException(e.getErrorCode(), e.getErrorMessage(), e);
                    } catch (Exception e) {
                        Trace.log(Trace.MODULE_INTERCEPTOR, Trace.LEVEL_ERROR, "aes decrypt error!!==========>>>{}", e);
                        throw new AccessControlException(ErrorEnum.decryptError.code(), ErrorEnum.decryptError.msg(),
                            e);
                    }
                }
            }
        }
        return headerMap;
    }

    private void chechIdBlackList(String idType, String blackType, ErrorEnum errorCode) {
        if (idType != null && idType.length() != 0) {
            if (ipBlackAndWhiteBean.inBlacklist(blackType, idType)) {
                throw new AccessControlException(errorCode.code(), String.format(errorCode.msg()));
            }
        }
    }

    public String getParamValue(ServerHttpRequest request, String key) {
        if (request.getQueryParams().containsKey(key)) {
            return request.getQueryParams().getFirst(key);
        }
        return null;
    }

    public String getHeaderValue(ServerHttpRequest request, String key) {
        if (request.getHeaders().containsKey(key)) {
            return request.getHeaders().getFirst(key);
        }
        return null;
    }

    @Override
    public int getOrder() {
        return -8;
    }

    private String getAndCheckParam(ServerHttpRequest request, ClogicContext clogicContext, String key, String desc) {
        String value = getValueByKey(request, clogicContext, key);
        // appId必须存在
        if (!StringUtil.hasText(value)) {
            throw new AccessControlException(ErrorEnum.paramNoFoundError.code(),
                String.format(ErrorEnum.paramNoFoundError.msg(), key, desc));
        }
        return value;
    }

    private String getValueByKey(ServerHttpRequest request, ClogicContext clogicContext, String key) {
        String value = (String)clogicContext.getValue(key);
        if (!StringUtil.hasText(value)) {
            value = this.getHeaderValue(request, key);
        }
        if (!StringUtil.hasText(value)) {
            value = this.getParamValue(request, key);
        }
        return value;
    }
}
